<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>testArea</title>
    <script type="text/javascript" src="../doc/asset/js/esl/esl.js"></script>
</head>
<body>
    <script type="text/javascript">
    require.config({
        packages: [
            {
                name: 'zrender',
                location: '../src',
                main: 'zrender'
            }
        ]
    });
        var zr;
        var shape;
        var isInside;
        var isOutside;
        var _util;
        var _ctx;
        var _shape;
        var index = 0;

    require(
        [
            "zrender",
            "zrender/tool/area",
            'zrender/tool/util',
            'zrender/shape/Line',
            'zrender/shape/BezierCurve',
            'zrender/shape/Polyline',
            'zrender/shape/Ring',
            'zrender/shape/Rectangle',
            'zrender/shape/Sector',
            'zrender/shape/Polygon',
            'zrender/shape/Circle'
        ], 
        function(zrender, area, util,
            LineShape, 
            BezierCurveShape, 
            BrokenLineShape, 
            RingShape, 
            RectangleShape, 
            SectorShape,
            PolygonShape, 
            CircleShape
        ){

            function render () {
                zr.clear();
                shape = randomShape();
                zr.addShape( shape );
                zr.render();
            }

            document.getElementById('btn-create').onclick = render;
            document.getElementById('btn-test').onclick = test;

            // 初始化zrender
            zr = zrender.init( document.getElementById("Main") );
            render();

            isInside = area.isInside;
            isOutside = area.isOutside;

            _util = util;
            _shape = shape;

            // 生成shape
            function randomShape() {
                index ++;
                var Clazz = [
                    LineShape, 
                    BezierCurveShape, 
                    BrokenLineShape, 
                    RingShape, 
                    RectangleShape, 
                    SectorShape,
                    PolygonShape, 
                    CircleShape
                ][index % 8];

                return new Clazz({
                    position : [random(600), random(400)],
                    scale : [1, 1],
                    style : {
                        x : 50,
                        y : 50,
                        a : 50,
                        b: 50,
                        r : random(200),
                        xStart : random(600),
                        yStart : random(400),
                        cpX1 : 100,
                        cpY1 : 100,
                        startAngle : 0,
                        endAngle: random(360),
                        xEnd : random(600),
                        yEnd : random(400),
                        width : random(600),
                        height : random(400),
                        pointList : [[10, 10], [300, 20], [298, 400], [50, 450]],
                        color : 'rgba(220, 20, 60, 0.8)',
                        strokeColor : "rgba(220, 20, 60, 0.8)",
                        lineWidth : 5,
                        brushType : 'stroke',
                        text :'test',
                        textPosition :'inside'
                    },
                    draggable: true
                });
            }

            // 测试耗时
            function test() {
                var n = 60;
                var m = 40;
                if (!_ctx) {
                    _ctx = _util.getContext();
                }
                // 计算纯数学方法耗时
                var time = new Date().getTime();
                for (var i = 0; i < n ; i ++ ) {
                    for (var j = 0; j < m ; j ++ ) {
                        testSwitch(shape, shape.style, i , j)
                    }
                }
                $('switch').innerHTML = new Date().getTime() - time;

                // 计算buildPath方法耗时
                time = new Date().getTime();

                for (var i = 0; i < n ; i ++ ) {
                    for (var j = 0; j < m ; j ++ ) {
                        testBuildPath(shape, shape.style, i , j)
                    }
                }
                $('build').innerHTML = new Date().getTime() - time;

                // 计算获取像素方法耗时
                time = new Date().getTime();

                for (var i = 0; i < n ; i ++ ) {
                    for (var j = 0; j < m ; j ++ ) {
                        testPixel(shape, shape.style, i , j)
                    }
                }
                $('pixel').innerHTML = new Date().getTime() - time;
            }

            // 测试buildPath
            function testBuildPath(shape, area, x, y) {
                // 图形类实现路径创建了则用类的path
                _ctx.beginPath();
                shape.buildPath(_ctx, area);
                _ctx.closePath();
                return _ctx.isPointInPath(x, y);
            }

            // 测试获取像素方法
            function testPixel(shape, area, x, y) {
                _ctx.clearRect(0, 0, 600, 400);
                _ctx.beginPath();
                shape.brush(_ctx, shape);
                _ctx.closePath();

                isPainted(_ctx, x, y);
            }

            // 判断坐标是否已经被画过
            function isPainted(context, x, y, unit) {
                var unit = unit || 1;
                var pixels;

                if (unit) {
                    pixels = context.getImageData(x - Math.floor(unit / 2), y - Math.floor(unit / 2), unit, unit);
                }
                else {
                    pixels = context.getImageData(x, y, 1, 1);
                }

                var data = pixels.data;
                var len = data.length;

                for (var i = 0 ; i < len ; i++) {
                    if (data[i] != 0) {
                        return true;
                    }
                }
                return false;
            }

            /**
             * 测试纯数学计算
             */
            function testSwitch(shape, area, x, y) {
                switch (shape.type) {
                    //线-----------------------1
                    case 'line':
                        return _isInsideLine(area, x, y);
                    //折线----------------------2
                    case 'polyline':
                        return _isInsidePolyline(area, x, y);
                    //文本----------------------3
                    case 'text':
                        return true;
                    //圆环----------------------4
                    case 'ring':
                        return _isInsideRing(area, x, y);
                    //矩形----------------------5
                    case 'rectangle':
                        return true;
                    //圆形----------------------6
                    case 'circle':
                        return _isInsideCircle(area, x, y);
                    //扇形----------------------7
                    case 'sector':
                        return _isInsideSector(area, x, y);
                    //多边形---------------------8
                    case 'polygon':
                        return _isInsidePolygon(area, x, y);
                    //图片----------------------9
                    case 'image':
                        return true;
                    //心形----------------------10
                    case 'heart':
                        return true;    // Todo，不精确
                    //水滴----------------------11
                    case 'droplet':
                        return true;    // Todo，不精确
                    //椭圆----------------------12
                    case 'ellipse':
                        return false;    // Todo，不精确
                    //路径----------------------13
                    case 'path':
                        return false;   // Todo，暂不支持
                }
            }

            /**
             * 线段包含判断
             */
            function _isInsideLine(area, x, y) {
                //水平、垂直快捷判断
                if (area.xStart == area.xEnd) {
                    //垂直线判断
                    return area.yStart <= y
                           && area.yEnd >= y
                           && Math.abs(area.xStart - x) < (area.lineWidth || 1);
                }
                if (area.yStart == area.yEnd){
                    //水平线判断
                    return area.xStart <= x
                           && area.xEnd >= x
                           && Math.abs(area.yStart - y) < (area.lineWidth || 1);
                }

                //斜线判断
                return Math.abs(
                           Math.abs(
                               (area.xStart - x)
                               * (area.yStart - area.yEnd) / (area.xStart - area.xEnd)
                               - area.yStart
                           )
                           - y
                      )
                      < (area.lineWidth || 1);
            }

            function _isInsidePolyline(area, x, y) {
                var pointList = area.pointList;
                var lineArea;
                var insideCatch = false;
                for (var i = 0, l = pointList.length - 1; i < l; i++) {
                    lineArea = {
                        xStart : pointList[i][0],
                        yStart : pointList[i][1],
                        xEnd : pointList[i + 1][0],
                        yEnd : pointList[i + 1][1],
                        lineWidth : area.lineWidth
                    };
                    insideCatch = isInside(LineShape.prototype, lineArea, x, y);
                    if (insideCatch) {
                        break;
                    }
                }
                return insideCatch;
            }

            function _isInsideRing(area, x, y) {
                if (isInside(CircleShape.prototype, area, x, y)
                    && isOutside(
                        CircleShape.prototype,
                        {
                            x : area.x,
                            y : area.y,
                            r : area.r0 || 0
                        },
                        x, y
                    )
                ){
                    // 大圆内，小圆外
                    return true;
                }
                return false;
            }

            /**
             * 矩形包含判断
             */
            function _isInsideRectangle(area, x, y) {
                if (x >= area.x
                    && x <= (area.x + area.width)
                    && y >= area.y
                    && y <= (area.y + area.height)
                ) {
                    return true;
                }
                return false;
            }

            /**
             * 圆形包含判断
             */
            function _isInsideCircle(area, x, y) {
                return (x - area.x) * (x - area.x) + (y - area.y) * (y - area.y)
                       < area.r * area.r;
            }

            /**
             * 扇形包含判断
             */
            function _isInsideSector(area, x, y) {
                if (isOutside('circle', area, x, y)
                    || (area.r0 > 0
                        && isInside(
                                CircleShape.prototype,
                                {
                                    x : area.x,
                                    y : area.y,
                                    r : area.r0
                                },
                                x, y
                            )
                        )
                ){
                    // 大圆外或者小圆内直接false
                    return false;
                }
                else {
                    // 判断夹角
                    var angle = (360
                                 - Math.atan2(y - area.y, x - area.x) / Math.PI
                                 * 180)
                                 % 360;
                    return (angle >= area.startAngle && angle <= area.endAngle);
                }
            }

            /**
             * 多边形包含判断
             * 警告：下面这段代码会很难看，建议跳过~
             */
            function _isInsidePolygon(area, x, y) {
                /**
                 * 射线判别法
                 * 如果一个点在多边形内部，任意角度做射线肯定会与多边形要么有一个交点，要么有与多边形边界线重叠
                 * 如果一个点在多边形外部，任意角度做射线要么与多边形有一个交点，
                 * 要么有两个交点，要么没有交点，要么有与多边形边界线重叠。
                 */
                var i;
                var j;
                var polygon = area.pointList;
                var N = polygon.length;
                var inside = false;
                var redo = true;
                var v;
                var left = 0;
                var right = 0;

                for (i = 0; i < N; ++i) {
                    // 是否在顶点上
                    if (polygon[i][0] == x && polygon[i][1] == y ) {
                        redo = false;
                        inside = true;
                        break;
                    }
                }

                if (redo) {
                    redo = false;
                    inside = false;
                    for (i = 0,j = N - 1;i < N;j = i++) {
                        if ((polygon[i][1] < y && y < polygon[j][1])
                            || (polygon[j][1] < y && y < polygon[i][1])
                        ) {
                            if (x <= polygon[i][0] || x <= polygon[j][0]) {
                                v = (y - polygon[i][1])
                                    * (polygon[j][0] - polygon[i][0])
                                    / (polygon[j][1] - polygon[i][1])
                                    + polygon[i][0];
                                if (x < v) {          // 在线的左侧
                                    inside = !inside;
                                }
                                else if (x == v) {   // 在线上
                                    inside = true;
                                    break;
                                }
                            }
                        }
                        else if (y == polygon[i][1]) {
                            if (x < polygon[i][0]) {    // 交点在顶点上
                                polygon[i][1] > polygon[j][1] ? --y : ++y;
                                //redo = true;
                                break;
                            }
                        }
                        else if (polygon[i][1] == polygon[j][1] // 在水平的边界线上
                                 && y == polygon[i][1]
                                 && ((polygon[i][0] < x && x < polygon[j][0])
                                     || (polygon[j][0] < x && x < polygon[i][0]))
                        ) {
                            inside = true;
                            break;
                        }
                    }
                }
                return inside;
            }
        })

        // 渲染canvas
        

        

        function $(id) {
            return document.getElementById(id);
        }

        

        // 随机一个整数
        function random(max) {
            return Math.min(Math.floor(Math.random() * (max + 1)), max);
        }

        
    </script>
    <div id="Main" style="width:600px;height:400px;"></div>
    <input type="button" value="生成图形" id="btn-create"/>
    <input type="button" value="test" id="btn-test"/>
    <h3>从(1,1)到(600,400)执行下面的方法</h3>
    <p >switch的那一坨耗时 <span id="switch"></span> ms</p>
    <p >buildPath耗时 <span id="build"></span> ms</p>
    <p >像素判断耗时 <span id="pixel"></span> ms</p>
</body>
</html>